react hooksのみで快適flux生活
react hooksでfluxをサクッとやるstore.jsです
example
https://github.com/miyamonz/use-reducer-example
以下に書くstore.jsを用意する
main.jsで自分のApp コンポーネントを <Provider>でwrapする
コンポーネントの中ではこんな感じで使える
code:js
import useStore from './store'
const addTodo = newTodo => ({todos}) => ({ todos: ...todos, newTodo })
function Hoge() {
const state, dispatch = useStore();
function onClick(e) {
dispatch(addTodo(e.target.value));
}
return (
<>
{state.todos.map(text => <li>{text}</li>)}
<button onClick={onClick}> add </button>
/<>
)
}
こういう感じでstateを更新する関数addTodoを作ってdispatchに渡せば良くなる
その場ですぐに param => state => newstateな関数を作ればいい
必要なら別ファイルにまとめてimportして使い回す
これでどこからでも直ちにglobal stateを引っ張ってdispatchもできる
不要なpropsバケツリレーが無くなる
code:store.js
import React, { useReducer, useContext } from "react";
export const Store = React.createContext();
function reducer(prev, newState) {
//第2引数はuseStore使ってる側から渡されるもの
// 関数だったらprev渡して、そうじゃなかったらこれ自体が新しいstateの内容物というAPIにしている↓
const _newState = typeof newState === "function" ? newState(prev) : newState;
// もしreduxに設計を寄せたいなら、
// ここで第2引数が{type: "ADD_TODO", ...}のようなreduxにおけるアクションのobjectだったら、
//それごとの処理をする内容などを書いてもいいと思う
return {...prev, ..._newState};
};
export const Provider = ({ children, initialState }) => {
const state, dispatch = useReducer(reducer, initialState);
return (
<Store.Provider value={ state, dispatch }>{children}</Store.Provider>
);
};
export function useStore() {
return useContext(Store);
}
reducerのactionを関数も受けられるようにしている
reduxの場合
アクションオブジェクトをdispatchする
こんなの{type: "ADD_TODO" payload: {ここに何らかの引数的な情報} }
今回の場合
stateを変更したいのだから
「stateを引数として新しいstateを返す関数」を渡せばいい
payload的な情報を渡すことを考えると
payload => prevState => newStateみたいな形の関数を用意して部分適用みたいな風にするといい
関数じゃなくてオブジェクトを渡したら元のstateにマージされる
これはほとんどuseStateと同じAPI
ちなみにreducer内でオブジェクトのマージするようにするとactionを書くのが少し楽になる
keyを消したいときは面倒かもしれん
しかし普通stateのkeyは増減しないし良さそう
下階層も考慮したい
あとでやる
main.jsではこうやる
code:js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "./store";
import App from "./App";
const initialState = {
todos: "hoge", "hoge2"
};
ReactDOM.render(
<Provider initialState={initialState}>
<App />
</Provider>,
document.querySelector("#app")
);
redux不要論に色々書いたが
本当に一切reduxが不要になるかはまだわからない
しかし、最初の一歩としては良い気がする
あとからreduxに切り替えるのも大変には見えない
そもそもfluxという点で設計は同じなので
似た記事もあった
https://medium.com/maxime-heckel/rebuilding-redux-with-hooks-and-context-e16b59faf51c
https://qiita.com/nishiurahiroki/items/d2733e7108e6e59a9930
https://qiita.com/yarnaimo/items/28b409f7a4de7d65e490
これはtypescriptでちゃんと型も入れてる
関係ないけどtypescriptでtsとtsx間違えるの注意
https://qiita.com/ossan-engineer/items/1192c224e4252ec0f421